package devcken.taglibrary;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

/**
 * 열거형 태그를 이용해 HTML 텍스트 태그를 렌더링하기 위한 태그 핸들러로 {@link javax.servlet.jsp.tagext.BodyTagSupport BodyTabSupport}를 확장한다.
 * 텍스트 태그를 만들기 위해 XML 문서 도구를 이용한다.
 * @author Devcken
 */
public class EnumerationViewTag extends BodyTagSupport
{
	private static final long serialVersionUID = -326283084621324099L;
	
	private static final Logger logger = LoggerFactory.getLogger(EnumerationTagLoader.class);
	
	/**
	 * 텍스트 태그 식별을 위한 상수 목록으로 switch 문 사용을 위해 해쉬 코드를 이용한다.
	 */
	private final int _VIEW_TYPE_LABEL = 102727412; // label
	private final int _VIEW_TYPE_LINK = 3321850; // link(a tag)
	
	/**
	 * 열거형 태그 관리자로 Input 태그를 위한 열거형 태그를 가져오기 위해 사용된다.
	 */
	private EnumerationTagLoader _enumerationTagLoader;
	
	/**
	 * 열거형 태그의 명칭으로 일치하는 열거형 태그를 가져오기 위해 반드시 설정되어야 한다.
	 */
	private String code;
	
	/**
	 * 렌더링하고자 하는 태그의 타입으로 실제 HTML 태그명으로 반드시 설정되어야 한다.
	 */
	private String type;
	
	/**
	 * 텍스트 태그로 나타내고자 하는 열거형 태그 상수의 값으로 반드시 설정되어야 한다.
	 */
	private String value;
	
	/**
	 * 링크 태그의 url 속성을 나타낸다.
	 */
	private String url;
	
	/**
	 * 텍스트 태그에 CSS을 설정하기 위한 값(class 속성)을 나타낸다. 필수 사항은 아니다.
	 */
	private String style;
	
	/**
	 * 텍스트 태그 유형에 맞는 텍스트 태그 문자열을 생성한다.
	 * @return 열거형 태그에 맞는 텍스트 태그 문자열을 반환한다.
	 */
	private String generateTag()
	{
		String result = "";
		
		try
		{
			EnumerationTag tag = this._enumerationTagLoader.getTag(this.code);
			EnumerationTagAttribute attribute = tag.getAttribute(this.value);
			
			switch (this.type.hashCode())
			{
				case _VIEW_TYPE_LABEL:
					
					result = this.generateLabelTag(attribute.getName());
					
					break;
					
				case _VIEW_TYPE_LINK:
					
					result = this.generateLinkTag(attribute.getName());
					
					break;
			}
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return result;
	}
	
	/**
	 * 라벨 태그 문자열을 생성한다.
	 * @param tag 열거형 태그를 설정한다.
	 * @return 열거형 태그에 해당하는 라벨 태그 문자열을 반환한다.
	 */
	private String generateLabelTag(String name)
	{
		try
		{
			Document document = DocumentHelper.createDocument();
			
			Element label = document.addElement("label");
			
			label.setText(name);
			
			if (!this.style.equals(""))
			{
				label.addAttribute("class", this.style);
			}
			
			return label.asXML();
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
			
			return "";
		}
	}
	
	/**
	 * 링크(a) 태그 문자열을 생성한다.
	 * @param tag 열거형 태그를 설정한다.
	 * @return 열거형 태그에 해당하는 링크 태그 문자열을 반환한다.
	 */
	private String generateLinkTag(String name)
	{
		try
		{
			Document document = DocumentHelper.createDocument();
			
			Element link = document.addElement("a");
			
			link.setText(name);
			
			if (this.url != null && !this.url.equals(""))
			{
				link.addAttribute("href", this.url);
			}
			
			if (this.style != null && !this.style.equals(""))
			{
				link.addAttribute("class", this.style);
			}
			
			return link.asXML();
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
			
			return "";
		}
	}
	
	/**
	 * HTML 태그 렌더링을 준비한다.
	 */
	@Override
	public int doStartTag() throws JspException
	{
		try
		{
			WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(this.pageContext.getServletContext());
			
			this._enumerationTagLoader = (EnumerationTagLoader)context.getBean("enumerationTagLoader");
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return super.doStartTag();
	}
	
	/**
	 * HTML 태그를 만들어 페이지에 쓴다.
	 */
	@Override
	public int doEndTag() throws JspException
	{
		if (this._enumerationTagLoader == null)
		{
			logger.warn("Tag genration is impossible.");
			
			return EVAL_PAGE;
		}
		
		try
		{
			// HTML 태그를 만든다.
			String tag = this.generateTag();
			
			JspWriter writer = pageContext.getOut();
			
			writer.print(tag);
			writer.flush();
		}
		catch (IOException error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return EVAL_PAGE;
	}

	public String getCode()
	{
		return code;
	}

	public void setCode(String code)
	{
		this.code = code;
	}

	public String getType()
	{
		return type;
	}

	public void setType(String type)
	{
		this.type = type;
	}

	public String getValue()
	{
		return value;
	}

	public void setValue(String value)
	{
		this.value = value;
	}

	public String getUrl()
	{
		return url;
	}

	public void setUrl(String url)
	{
		this.url = url;
	}

	public String getStyle()
	{
		return style;
	}

	public void setStyle(String style)
	{
		this.style = style;
	}
}